/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
// promise有三个状态 分别是等待、成功、失败
/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
// promise有三个状态 分别是等待、成功、失败
const PENGIN = 'pengin';
const FULFILLED = 'fulfilled';
const REJECTED = 'reject';

class MyPromise {
    constructor(fn) {
        fn(this.resolve, this.reject);
    }
    // 状态
    status = PENGIN;
    // 成功值
    value = undefined;
    // 失败值
    reason = undefined
    // 成功proimse集合
    successCallback = [];
    // 失败promise集合
    failCallback = [];
    // 成功
    resolve = value => {
        // 如果不是等待状态久直接退出 
        if ( this.status != PENGIN ) return false;
        // 更改状态
        this.status = FULFILLED;
        // 写入传进来的值
        this.value = value;
        // 如果成功回调不为亏则取出第一个执行  直到为空暂停
        while(this.successCallback.length) this.successCallback.shift()();
    }
    // 失败
    reject = reason => {
        // 如果结果是成功、失败久不能改变结果
        if ( this.status != PENGIN ) return false;
        this.status = REJECTED;
        this.reason = reason;
        while(this.failCallback.length) this.failCallback.shift()();
    }
    then(successCallback, failCallback) {
        // 参数可选 
        successCallback = successCallback ? successCallback : value => value;
        failCallback = failCallback ? failCallback : reason => { throw reason };
        // 因为then可以链式调用，所以这里得返回一个promise
        let pr = new MyPromise((resolve, reject) => {
            // 同步成功 直接调用
            if(this.status === FULFILLED) {
                // 因为里面需要拿到pr所以这里使用setTimeout将下面变成宏任务
                setTimeout( _ => {
                    let x = successCallback(this.value);
                    resolvePromise(pr, x, resolve, reject);
                },0);
            } 
            // 同步失败 直接调用
            else if (this.status === REJECTED) {
                setTimeout( _ => {
                    let x = failCallback(this.reason);
                    resolvePromise(pr, x, resolve, reject);
                },0);
            }
            // 异步回调先存储
            else {
                // 存储成功
                this.successCallback.push(() => {
                    setTimeout( _ => {
                        let x = successCallback(this.value);
                        resolvePromise(pr, x, resolve, reject);
                    },0);
                })
                // 存储失败
                this.failCallback.push(() => {
                    setTimeout( _ => {
                        let x = failCallback(this.reason);
                        resolvePromise(pr, x, resolve, reject);
                    },0)
                })
            }
        })
        return pr;
    }
    // 无论是成功或者失败都会执行
    finally(callback) {
        // 返回一个promise
        return this.then(value => {
            return MyPromise.resolve(callback()).then( () => value );
        },reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason });
        })
    }
    static resolve(value) {
        // 如果传进来的是promise的话 就直接返回
        if (value instanceof MyPromise) return value;
        // 生成一个promise返回
        return new MyPromise(resolve => resolve(value));
    }
    // 我传进来的条数和我执行后的条数如果一致就返回成功的结果
    static all(array) {
        let result = {},
            index = 0;
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                // 存储结果
                result[key] = value;
                // 记录执行条数
                index++;
                // 如果执行条数与传进来的条数一致 就成功
                if ( index === array.length ) {
                    resolve(result);
                }
            }
            for(let i = 0; i < array.length; i++) {
                // 如果是promise就执行then
                if ( array[i] instanceof MyPromise ) {
                    array[i].then(value => addData(i, value), reason => reject(reason));
                } else {
                    addData(i, array[i]);
                }
            }
        })
    }
    catch(failCallback) {
        this.then(undefined, failCallback)
    }
}
function resolvePromise(pr, x, resolve, reject) {
    if ( pr === x ) {
        return ''
    }
    // 如果是一个proimse就执行then
    if ( x instanceof MyPromise ) {
        x.then(resolve, reject);
    }
    // 如果是普通的回调就直接调用 
    else {
        resolve(x);
    }
}

module.exports = MyPromise;